package com.example.cuckoofilterdemo.service.impl;

import com.example.cuckoofilterdemo.dao.ProductDao;
import com.example.cuckoofilterdemo.exception.BusinessException;
import com.example.cuckoofilterdemo.exception.ErrorCode;
import com.example.cuckoofilterdemo.filter.CuckooFilterService;
import com.example.cuckoofilterdemo.model.Do.ProductDO;
import com.example.cuckoofilterdemo.model.vo.ProductVO;
import com.example.cuckoofilterdemo.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class ProductServiceImpl implements ProductService {
    private static final String PRODUCT_CACHE_PREFIX = "product:";
    private static final String PRODUCT_NULL_CACHE_PREFIX = "product:null:";
    private static final long CACHE_EXPIRE_SECONDS = 3600; // 1小时
    private static final long NULL_CACHE_EXPIRE_SECONDS = 300; // 5分钟

    private final RedisTemplate<String, Object> redisTemplate;
    private final ProductDao productDao;
    private final CuckooFilterService cuckooFilterService;

    @Autowired
    public ProductServiceImpl(RedisTemplate<String, Object> redisTemplate,
                              ProductDao productDao,
                              CuckooFilterService cuckooFilterService) {
        this.redisTemplate = redisTemplate;
        this.productDao = productDao;
        this.cuckooFilterService = cuckooFilterService;
    }

    @Override
    public ProductVO getProductById(Long id) {
        // 1. 参数校验
        if (id == null || id <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "商品ID不合法");
        }

        String cacheKey = PRODUCT_CACHE_PREFIX + id;
        String nullCacheKey = PRODUCT_NULL_CACHE_PREFIX + id;

        // 2. 先查询布谷鸟过滤器
        if (!cuckooFilterService.mightContain(String.valueOf(id))) {
            log.info("Product {} not exist in cuckoo filter", id);
            return null;
        }

        // 3. 查询缓存
        ProductVO productVO = getFromCache(cacheKey);
        if (productVO != null) {
            return productVO;
        }

        // 4. 检查空值缓存
        if (Boolean.TRUE.equals(redisTemplate.hasKey(nullCacheKey))) {
            log.info("Product {} is marked as non-existent", id);
            return null;
        }

        // 5. 查询数据库
        ProductDO productDO = productDao.getProductById(id);
        if (productDO == null) {
            // 将空值缓存起来，防止缓存穿透
            redisTemplate.opsForValue().set(nullCacheKey, "NULL", NULL_CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);
            // 将ID加入布谷鸟过滤器
            cuckooFilterService.add(String.valueOf(id));
            return null;
        }

        // 6. 转换并缓存结果
        productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        redisTemplate.opsForValue().set(cacheKey, productVO, CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);

        return productVO;
    }

    private ProductVO getFromCache(String key) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            if (value instanceof ProductVO) {
                return (ProductVO) value;
            }
        } catch (Exception e) {
            log.error("Get product from cache error, key: {}", key, e);
        }
        return null;
    }
}
